using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using KnowledgeKiosk.Objects;

namespace KnowledgeKiosk.Parsers
{
    /// <summary>
    /// Provides a way to deserialize XML data to Course objects. 
    /// </summary>
    public class CoursesParser : IXmlToObjectParser<IEnumerable<Course>>
    {
        private static readonly XNamespace rs = "urn:schemas-microsoft-com:rowset";
        private static readonly XNamespace z = "#RowsetSchema";

        #region IXmlToObjectParser<IEnumerable<Course>> Members

        /// <summary>
        /// Deserializes XML to a collection of Course objects.
        /// </summary>
        /// <param name="xml">The XML data to deserialize.</param>
        /// <returns>The deserialized collection of Course objects.</returns>
        public IEnumerable<Course> Parse(XElement xml)
        {
            return xml.Element(rs + "data").Elements(z + "row").Select(x => ToCourse(x)).ToList();
        }

        #endregion

        /// <summary>
        /// Attempts to parse a SharePoint character separated attribute string into a strongly typed Photo object.
        /// </summary>
        /// <param name="photoString">A string in SharePoint CSV format.</param>
        /// <param name="result">When this method returns, contains the Photo object parsed from the data contained
        /// in photoString, if the conversion succeeded, or null if the conversion failed.</param>
        /// <returns>True if photoString was parsed succesfully; otherwise, false.</returns>
        private static bool TryParsePhotoString(string photoString, out Photo result)
        {
            result = null;
            string[] values = photoString.Split(new[] {";#"}, StringSplitOptions.None);
            if (values.Length == 5
                && !String.IsNullOrEmpty(values[1])
                && !String.IsNullOrEmpty(values[2])
                && values[2] != "None")
            {
                try
                {
                    result = new Photo
                                 {
                                     Name = values[2],
                                     Url = new Uri(values[1], UriKind.Absolute)
                                 };
                    return true;
                }
                catch
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Deserializes XML data to a single Course object.
        /// </summary>
        /// <param name="node">The XML data to deserialize.</param>
        /// <returns>The deserialized Course object.</returns>
        private static Course ToCourse(XElement node)
        {
            var course = new Course();
            course.Title = (string) node.Attribute("ows_Title") ?? "<Naamloos>";
            course.Room = (string) node.Attribute("ows_Lokaal") ?? "?";
            string teacherInternal = (string) node.Attribute("ows_Docent") ?? String.Empty;
            string teacherExternal = (string) node.Attribute("ows_Externe_x0020_docent") ?? String.Empty;
            Photo teacher;
            if (TryParsePhotoString(teacherInternal, out teacher) || TryParsePhotoString(teacherExternal, out teacher))
                course.Trainer = teacher;
            else
                course.Trainer = new Photo
                                     {
                                         Name = "Onbekend Persoon", 
                                         Url = new Uri(@"Images/Unknown Person.png", UriKind.Relative)
                                     };
            return course;
        }
    }
}